package com.mingqijia.gassafety.shared.vcc;

import java.util.Arrays;
import java.util.Date;


import cn.hutool.core.lang.TypeReference;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.*;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.gap.basic.exception.BizException;
import com.gap.cache.redis.RedisCache;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.dto.TcConsumerDTO;
import com.mingqijia.gassafety.shared.handler.GlobalAuthenticationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Type;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class VccAuthoritiesProvider {
    @Value(value = "${h5.useOpenIdBindSubs.orgIds:}")
    private String useOpenIdBindSubsOrgIds;

//    @Autowired
//    private GoodServiceFeign goodServiceFeign;

    private final VccTokenCodeConfig tokenCodeConfig;

    private final VccTokenClientConfig tokenClientConfig;

    private final VccH5ClientConfig vccH5ClientConfig;

    @Autowired
    RedisCache redisCache;

    private static final String TEMPLATE_SIGN = "openSignVersion=2&openTimestamp=%s%s";
    private static final String TEMPLATE_STRING = "openTimestamp=%s&openSign=%s&openSignVersion=2";

    /** 1004 获取用户信息 */
    private static final String URL_USER_INFO = "%s/open-business-normal/bridge/v1/oauth/user?%s";
    /** 2001 获取用户详细信息 */
    private static final String URL_USER_DETAIL = "%s/open-business-normal/bridge/v1/uum/user/account/token?%s";
    /** 2002 获取可登录的企业 */
    private static final String URL_AVAILABLE_SP = "%s/open-business-normal/bridge/v1/uum/user/users/availableSp?%s";
    /** 2003 切换企业 */
    private static final String URL_CHANGE_SP = "%s/open-business-normal/bridge/v1/oauth/chsp?%s";
    /** 2004 查询⻚面菜单 */
    private static final String URL_PAGE_MENU = "%s/open-business-normal/bridge/v1/plat/configuration/menus/list?dataType=operatePriv&applicationCode=%s&%s";
    /** 2005 获取用户权限 */
    private static final String URL_FUNC_PRIV = "%s/open-business-normal/bridge/v1/uum/user/thirdprivileges/operatePriv?applicationCode=%s&%s";
    /**
     * 3001 同步部⻔数据
     */
    private static final String URL_ORG_INFO = "%s/open-business-normal/bridge/mv1/uum/org/orgs/all?stdCode=%s&updateTime=%s&pageIndex=%s&pageSize=%s&%s";

    private static final String URL_ORG_INFO_TEL = "%s/open-business-openapi/api/open/enc/org/orgInfo?orgCode=%s&%s";
    /** 3002 同步JV员工数据 */
    private static final String URL_USER_STAFF = "%s/open-business-normal/bridge/mv1/uum/org/orgs/staffs?staffCode=%s&stdCode=%s&updateTime=%s&pageIndex=%s&pageSize=%s&%s";
    /** 查询用户 */
    private static final String URL_USER_VCC = "%s/open-business-openapi/api/open/enc/user/getSubsByCode?orgCode=%s&subsCode=%s&%s";

    /** 2006 查询所有部门 */
    private static final String URL_ORG_ALL = "%s/open-business-normal/bridge/v1/uum/org/staffOrgs?%s";

    private static final String URL_STAFF_LIST = "%s/open-business-normal/bridge/v1/api/crm-service/staffNew?%s&pageIndex=%s&pageSize=%s";

    /** 查询vcc企业**/
    private static final String URL_ENTERPRISE_LIST = "%s/open-business-normal/bridge/v1/api/base/gas/getAllOrgs?%s";

    private static final String URL_CHILD_SPID = "%s/open-business-normal/bridge/mv1/uum/org/sp/childSpId?%s&spId=%s";

    /** 查询用户登录日志列表 */
    private static final String URL_LOGIN_RECORD = "%s/open-business-normal/bridge/sv1/crm/service/login/record/queryLoginRecordList?%s";

    /** 查询Vcc用户绑定的用户列表*/
    private static final String URL_QUERY_SUBS_USER_CODE =
            "%s/open-business-openapi/api/open/enc/user/querySubsByUserCode?%s&userCode=%s&userType=M";
    
    /** 使用openid查询Vcc用户绑定的用户列表*/
    private static final String URL_QUERY_SUBS_USER_CODE_BY_WX_OPENID =
            "%s/open-business-openapi/api/open/enc/user/querySubsByUserCode?%s&userId=%s";

    /** 查询vcc用户手机号*/
    private static final String TEMPLATE_QUERY_PHONE =
            "%s/open-business-openapi/api/open/user/getLoginPhoneByH5Token?%s&h5token=%s";

    /** 根据企业id查询企业信息 */
    private static final String QUERY_COMPANY_BY_SPID = "%s/uum/user/sp/queryCompanyBySpId";

    /**
     * 获取请求vcc客户列表的url
     * @param token
     * @return
     */
    public String getBindListUrl(String orgId, String token) {
        Map<String,String> userInfo = getVccUserInfo(token);
        String userPhone = null==userInfo?"":userInfo.get("phone");
        String userId = null==userInfo?"":userInfo.get("userId");
        if( !StringUtils.isEmpty(useOpenIdBindSubsOrgIds) ){
            List<String> orgIds = Arrays.asList(useOpenIdBindSubsOrgIds.split(","));
            if( orgIds.contains(orgId) ){
                return String.format(URL_QUERY_SUBS_USER_CODE_BY_WX_OPENID, tokenClientConfig.getServer(), sign4Client(), userId);
            }
        }
        return String.format(URL_QUERY_SUBS_USER_CODE, tokenClientConfig.getServer(), sign4Client(), userPhone);
    }


    /** 查询所有部门 */
    public JSONObject getEnterpriseList(String token) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_ENTERPRISE_LIST, tokenCodeConfig.getServer(), sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }


    /** 查询员工数据 */
    public JSONObject getStaffList(String token,String OrgId,int page,int pageSize,String phone,String position,
                                   String staffCode,String staffName,
                                   String empStatus,String staffType) {
        AtomicReference<String> dynamicUrl= new AtomicReference<>("");
        Map<String,Object> params = new HashMap<>();
        params.put("OrgId",OrgId);
        params.put("phone",phone);
        params.put("position",position);
        params.put("staffCode",staffCode);
        params.put("staffName",staffName);
        params.put("empStatus",empStatus);
        params.put("staffType",staffType);
        params.forEach((s, o) -> {
            if (o!=null) {
                dynamicUrl.set(dynamicUrl.get()+"&"+s + "=" + o);
            }
        });
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_STAFF_LIST+dynamicUrl.get(), tokenCodeConfig.getServer(), sign4Code(token),page,pageSize));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }



    /** 查询所有部门 */
    public JSONObject getOrgAll(String token) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_ORG_ALL, tokenCodeConfig.getServer(), sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }

    /** 获取用户信息 */
    public JSONObject getUserInfo(String token) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_USER_INFO, tokenCodeConfig.getServer(), sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }

    /** 获取用户详细信息 */
    public JSONObject getUserDetail(String token) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_USER_DETAIL, tokenCodeConfig.getServer(), sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }

    /** 获取可登录的企业 */
    public JSONObject getAvailableSp(String token) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_AVAILABLE_SP, tokenCodeConfig.getServer(), sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }

    /** 切换企业 */
    public JSONObject changeSpId(String token, String spId) {
        HttpRequest request = HttpUtil.createRequest(Method.POST,
                String.format(URL_CHANGE_SP, tokenCodeConfig.getServer(), sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        Map<String, String> params = new HashMap<String, String>() {{
            put("spId", spId);
        }};
        request.body(JSONUtil.toJsonStr(params), ContentType.JSON.getValue());
        return doHttpRequest(request);
    }

    /** 查询⻚面菜单 */
    public JSONObject getPageMenu(String token, String appCode) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_PAGE_MENU, tokenCodeConfig.getServer(), appCode, sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }

    /** 获取用户权限 */
    public JSONObject getUserPriv(String token, String appCode) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_FUNC_PRIV, tokenCodeConfig.getServer(), appCode, sign4Code(token)));
        request.header(Header.AUTHORIZATION, buildToken(token));
        return doHttpRequest(request);
    }

    /** 获取用户登录记录 */
    public JSONObject getLoginRecord(  String spId, String optBeginTime ,String optEndTime ) {
        HttpRequest request = HttpUtil.createRequest(Method.POST,
                String.format(URL_LOGIN_RECORD, tokenCodeConfig.getServer(), sign4Client()));
        request.header(Header.AUTHORIZATION, getTokenByClient());

        Map<String, Object> params = new HashMap<String, Object>() {{
            put("pageIndex",1);
            put("pageSize",400);
            put("spId", spId);
            put("optBeginTime", optBeginTime);
            put("optEndTime", optEndTime);
        }};
        log.info("查询用户登录记录:{}", JSONUtil.toJsonStr(params));
        request.body(JSONUtil.toJsonStr(params), ContentType.JSON.getValue());
        return doHttpRequest(request);
    }


    /** 同步部⻔数据  client模式 */
    public JSONObject getOrgInfo( String orgCode, String updateTime, int pageIndex, int pageSize) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_ORG_INFO, tokenCodeConfig.getServer(), orgCode, updateTime, pageIndex, pageSize, sign4Client()));
        request.header(Header.AUTHORIZATION, getTokenByClient());
        return doHttpRequest(request);
    }
    /** 获取企业号码 */
    public String getOrgInfoTel( String orgCode) {
        String tel = null;
        try {
            HttpRequest request = HttpUtil.createRequest(Method.GET,
                    String.format(URL_ORG_INFO_TEL, tokenCodeConfig.getServer(), orgCode,  sign4Client()));
            log.info("getOrgInfoTel-request:{}", String.format(URL_ORG_INFO_TEL, tokenCodeConfig.getServer(), orgCode,  sign4Client()));
            request.header(Header.AUTHORIZATION, getTokenByClient());
            tel =  doHttpRequest(request).getStr("tel");
            log.info("getOrgInfoTel-tel:{}",tel);
        } catch (Exception e) {
            log.info("getOrgInfoTel-err:{}",e);
            e.printStackTrace();
        }
        return tel;
    }

    /** 3002 同步JV员工数据  client模式 */
    public JSONObject getStaffs(String staffCode,String orgCode, String updateTime, int pageIndex, int pageSize) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_USER_STAFF, tokenCodeConfig.getServer(), staffCode,orgCode, updateTime, pageIndex, pageSize, sign4Client()));
        request.header(Header.AUTHORIZATION, getTokenByClient());
        return doHttpRequest(request);
    }

    /** 3002 同步VCC用户  client模式 */
    public JSONObject getVccUser(String orgCode, String subCode) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_USER_VCC, tokenCodeConfig.getServer(), orgCode, subCode, sign4Client()));
        request.header(Header.AUTHORIZATION, getTokenByClient());
        request.removeHeader(Header.ACCEPT_ENCODING);
        return doHttpRequest(request);
    }

    /** 3002 同步VCC用户  client模式 */
    public JSONObject getVccUserC(String orgCode, String subCode) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_USER_VCC, tokenCodeConfig.getServer(), orgCode, subCode, sign4Client()));
        request.header(Header.AUTHORIZATION, getTokenByClient());
        request.removeHeader(Header.ACCEPT_ENCODING);
        return doHttpRequestC(request);
    }

    /** 根据spId查询子公司 */
    public JSONObject getChildSpId(String spId) {
        HttpRequest request = HttpUtil.createRequest(Method.GET,
                String.format(URL_CHILD_SPID, tokenCodeConfig.getServer(), sign4Client(), spId));
        request.header(Header.AUTHORIZATION, getTokenByClient());
        request.removeHeader(Header.ACCEPT_ENCODING);
        return doHttpRequest(request);
    }

    private JSONObject doHttpRequest(HttpRequest request) {
        HttpResponse response = request.execute();
        log.info("doHttpRequest：{}", com.alibaba.fastjson.JSONObject.toJSONString(response));
        if (!Objects.equals(response.getStatus(), HttpStatus.HTTP_OK)) {
            log.error("调用{}失败, 返回：{}", request.getUrl(), response.body());
            throw new GlobalAuthenticationException(response.body());
        }
        log.info("调用{}, 返回:{}", request.getUrl(), response.body());
        JSONObject result = JSONUtil.parseObj(response.body());
        if (!Objects.equals(result.getInt("code"), Constants.INT_ZERO)) {
            log.error("数据请求失败：{}", response.body());
            throw new GlobalAuthenticationException(result.getStr("msg"));
        }
        return result.getJSONObject("data");
    }

    private String doHttpEwtRequest(HttpRequest request) {
        HttpResponse response = request.execute();
        log.info("doHttpRequest：{}", com.alibaba.fastjson.JSONObject.toJSONString(response));
        if (!Objects.equals(response.getStatus(), HttpStatus.HTTP_OK)) {
            log.error("调用{}失败, 返回：{}", request.getUrl(), response.body());
            throw new GlobalAuthenticationException(response.body());
        }
        log.info("调用{}, 返回:{}", request.getUrl(), response.body());
        String body = response.body();
        return body;
    }

    private JSONObject doHttpRequestC(HttpRequest request) {
        HttpResponse response = request.execute();
        log.info("doHttpRequest：{}", com.alibaba.fastjson.JSONObject.toJSONString(response));
        if (!Objects.equals(response.getStatus(), HttpStatus.HTTP_OK)) {
            log.error("调用{}失败, 返回：{}", request.getUrl(), response.body());
//            throw new GlobalAuthenticationException(response.body());
        }
        log.info("调用{}, 返回:{}", request.getUrl(), response.body());
        JSONObject result = JSONUtil.parseObj(response.body());
        if (!Objects.equals(result.getInt("code"), Constants.INT_ZERO)) {
            log.error("数据请求失败：{}", response.body());
//            throw new GlobalAuthenticationException(result.getStr("msg"));
        }
        return result.getJSONObject("data");
    }

    /** 签名 */
    private String sign4Code(String token) {
        String openAppSecret;
        if (StringUtils.isEmpty(token)) {
            openAppSecret = tokenCodeConfig.getOpenAppSecret();
        }
        else {
            String cacheStr = redisCache.getCacheStr(token);
            if (StringUtils.isEmpty(cacheStr)) {
                openAppSecret = tokenCodeConfig.getOpenAppSecret();
            }
            else {
                openAppSecret = cacheStr;
            }
        }
        Long second = Instant.now().getEpochSecond();
        String signStr = String.format(TEMPLATE_SIGN,
                second, openAppSecret);
        String signMd5 = SecureUtil.md5(signStr).toUpperCase();
        return String.format(TEMPLATE_STRING, second, signMd5);
    }

    /** 签名 */
    private String sign4Client() {
        Long second = Instant.now().getEpochSecond();
        String signStr = String.format(TEMPLATE_SIGN,
                second, tokenClientConfig.getOpenAppSecret());
        String signMd5 = SecureUtil.md5(signStr).toUpperCase();
        return String.format(TEMPLATE_STRING, second, signMd5);
    }

    private String getTokenByClient() {
        HttpRequest request = HttpUtil.createRequest(Method.POST,
                tokenClientConfig.getGenTokenUrl(sign4Code(null)));
        request.header(Header.CONTENT_TYPE, ContentType.JSON.getValue());
        request.body(JSONUtil.toJsonStr(tokenClientConfig));
        JSONObject token = doHttpRequest(request);
        return buildToken(token.getStr("token"));
    }

    private String buildToken(String token) {
        return token.startsWith(Constants.PREFIX_BEARER) ? token :
                Constants.PREFIX_BEARER + token;
    }

    public List<TcConsumerDTO> queryBindList(String orgId, String token) {
        log.info("查询绑定用户列表入参，orgId:{},token:{}", orgId, token);
        HttpRequest request = HttpUtil.createRequest(Method.GET, getBindListUrl(orgId, token));
        request.header(Header.AUTHORIZATION, tokenClientConfig.getToken());
        request.removeHeader(Header.ACCEPT_ENCODING);
        HttpResponse response = request.execute();
        if (!Objects.equals(response.getStatus(), HttpStatus.HTTP_OK)) {
            log.error("请求VCC接口失败{}，request={}, msg={}", request.getUrl(), JSONUtil.toJsonStr(request), response.body());
            throw new GlobalAuthenticationException("获取token失败");
        }
        JSONObject result = JSONUtil.parseObj(response.body());
        if (!Objects.equals(result.getInt("code"), Constants.INT_ZERO)) {
            log.error("请求VCC业务接口失败{}，msg={}", request.getUrl(), result);
            throw new GlobalAuthenticationException(result.getStr("msg"));
        }
        log.info("请求VCC业务接口成功{}，msg={}", request.getUrl(), result.getStr("data"));
        Type type = new TypeReference<List<TcConsumerDTO>>() {
        }.getType();
        List<TcConsumerDTO> list = JSON.parseObject(result.getStr("data"), type);
        List<TcConsumerDTO> newList =
                list.stream().filter(item -> orgId.equals(item.getOrgId())).collect(Collectors.toList());
        return newList;
    }

    public String getUserPhone(String token) {
        String phone ="";
        String openToken = vccH5ClientConfig.getToken();
        if(StringUtils.isEmpty(openToken)){
            throw new BizException("开放平台token获取失败");
        }
        String phoneUrl = String.format(TEMPLATE_QUERY_PHONE, vccH5ClientConfig.getServer(),sign4Client(), token);
        try {
            String body = com.mingqijia.gassafety.shared.utils.HttpUtil.getBody(phoneUrl, openToken);
            log.info("getPhone-response:{}", body);
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(body);
            if (Integer.parseInt(jsonObject.getString("code")) == 0) {
                com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
                phone = data.getString("mobile");
            }
        } catch (NumberFormatException e) {
            log.info("getPhone-error:{}",e);
            return null;
        }
        return phone;
    }


    /** 根据条件，参数查询所有企业 */
    public String queryCompany(List<String> spIds, String spName ,String scale, String url) {
        HttpRequest request = HttpUtil.createRequest(Method.POST,
                String.format(QUERY_COMPANY_BY_SPID, url));

        Map<String, Object> params = new HashMap<String, Object>() {{
            put("spIds", spIds);
        }};
        if (!StringUtils.isEmpty(spName)) {
            params.put("spName", spName);
        }
        if (!StringUtils.isEmpty(scale)) {
            params.put("scale", scale);
        }
        log.info("根据条件，参数查询所有企业:{}", JSONUtil.toJsonStr(params));
        request.body(JSONUtil.toJsonStr(params), ContentType.JSON.getValue());
        return doHttpEwtRequest(request);
    }

    /**
     * 根据token获取手机号和openId
     * @param token
     * @return
     */
    public Map<String,String> getVccUserInfo(String token) {
        String userId ="";
        String phone ="";
        String openToken = vccH5ClientConfig.getToken();
        if(StringUtils.isEmpty(openToken)){
            throw new BizException("开放平台token获取失败");
        }
        String phoneUrl = String.format(TEMPLATE_QUERY_PHONE, vccH5ClientConfig.getServer(),sign4Client(), token);
        try {
            String body = com.mingqijia.gassafety.shared.utils.HttpUtil.getBody(phoneUrl, openToken);
            log.info("getPhone-response:{}", body);
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(body);
            if (Integer.parseInt(jsonObject.getString("code")) == 0) {
                com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");
                userId = data.getString("userId");
                phone = data.getString("mobile");
                log.info("getUserPhoneOpenId phone:{},OpenId:{}", userId, phone);
            }
        } catch (NumberFormatException e) {
            log.info("getPhone-error:{}",e);
            return null;
        }
        Map<String,String> result = new HashMap<>();
        result.put("phone",phone);
        result.put("userId",userId);
        log.info("getUserPhoneOpenId result:{}", com.alibaba.fastjson.JSONObject.toJSONString(result));
        return result;
    }


}
